package com.tg.smsgw.ws;



import java.sql.*;
import java.util.*;

import telsoft.security.DBTableAuthenticator;
import telsoft.sql.Database;
import telsoft.util.AppException;
import telsoft.util.StringUtil;

/**
 * <p>Title: </p>
 * <p>Description: </p>
 * <p>Copyright: Copyright (c) 2003</p>
 * <p>Company: FSS-FPT</p>
 * @author Thai Hoang Hiep
 * @version 1.0
 */

public class AppAuthenticator extends DBTableAuthenticator
{
	////////////////////////////////////////////////////////
	private static Properties mprtPermissionCache = new Properties();
	private static Properties mprtPolicyCache = new Properties();
	private static long mlAuthenticationCacheDuration = 3600000;
	private static long mlClearTime = 0;
	private static long mlCheckTime = 0;
	private static String mstrLastAuthenticationChange = "";
	private static String mstrLastConfigurationChange = "";
	////////////////////////////////////////////////////////
	/**
	 *
	 * @return Properties
	 */
	////////////////////////////////////////////////////////
	static
	{
		try
		{
			mlAuthenticationCacheDuration = Long.parseLong(AppServer.getParam("AuthenticationCacheDuration")) * 1000;
		}
		catch(Exception e)
		{
		}
	}
	////////////////////////////////////////////////////////
	/**
	 *
	 * @return long
	 */
	////////////////////////////////////////////////////////
	public long getCacheDuration()
	{
		return mlAuthenticationCacheDuration;
	}
	////////////////////////////////////////////////////////
	/**
	 *
	 */
	////////////////////////////////////////////////////////
	public void updateClearTime()
	{
		mlClearTime = System.currentTimeMillis() + getCacheDuration() / 12; // 5 minute clear once
	}
	////////////////////////////////////////////////////////
	/**
	 *
	 * @return boolean
	 */
	////////////////////////////////////////////////////////
	public boolean shouldCheckCacheNow()
	{
		if(System.currentTimeMillis() > mlCheckTime)
		{
			try
			{
				checkAuthenticationChange(mcn);
				checkConfigurationChange(mcn);
				mlCheckTime = System.currentTimeMillis() + 60000;
			}
			catch(Exception e)
			{
			}
		}
		if(System.currentTimeMillis() > mlClearTime)
			return true;
		return false;
	}
	////////////////////////////////////////////////////////
	/**
	 *
	 * @return Properties
	 */
	////////////////////////////////////////////////////////
	public Hashtable getPermissionCache()
	{
		return mprtPermissionCache;
	}
	////////////////////////////////////////////////////////
	/**
	 *
	 * @param cn Connection
	 * @throws Exception
	 */
	////////////////////////////////////////////////////////
	public static void notifyAuthenticationChanged(Connection cn) throws Exception
	{
		Statement stmt = null;
		try
		{
			stmt = cn.createStatement();
			if(stmt.executeUpdate("UPDATE AP_PARAM SET PAR_VALUE=TO_CHAR(SYSDATE,'YYYYMMDDHH24MISS')" +
								  " WHERE PAR_NAME='AUTHENTICATION_LAST_CHANGED' AND PAR_TYPE='SYSTEM'") <= 0)
				stmt.executeUpdate("INSERT INTO AP_PARAM(PAR_VALUE,PAR_NAME,PAR_TYPE)" +
								   " VALUES (TO_CHAR(SYSDATE,'YYYYMMDDHH24MISS'),'AUTHENTICATION_LAST_CHANGED','SYSTEM')");
		}
		finally
		{
			Database.closeObject(stmt);
		}
	}
	////////////////////////////////////////////////////////
	/**
	 *
	 * @param cn Connection
	 * @throws Exception
	 */
	////////////////////////////////////////////////////////
	public static void notifyConfigurationChanged(Connection cn) throws Exception
	{
		Statement stmt = null;
		try
		{
			stmt = cn.createStatement();
			if(stmt.executeUpdate("UPDATE AP_PARAM SET PAR_VALUE=TO_CHAR(SYSDATE,'YYYYMMDDHH24MISS')" +
								  " WHERE PAR_NAME='CONFIGURATION_LAST_CHANGED' AND PAR_TYPE='SYSTEM'") <= 0)
				stmt.executeUpdate("INSERT INTO AP_PARAM(PAR_VALUE,PAR_NAME,PAR_TYPE)" +
								   " VALUES (TO_CHAR(SYSDATE,'YYYYMMDDHH24MISS'),'CONFIGURATION_LAST_CHANGED','SYSTEM')");
		}
		finally
		{
			Database.closeObject(stmt);
		}
	}
	////////////////////////////////////////////////////////
	/**
	 *
	 * @param strUserName String
	 * @param strPassword String
	 * @return String
	 * @throws Exception
	 */
	////////////////////////////////////////////////////////
	public String verifyPassword(String strUserName,String strPassword) throws Exception
	{
		if(!strUserName.toUpperCase().equals("ADMIN"))
			setAuthenticateHost(AppServer.getParam("Authen.Url"));
		try
		{
			return super.verifyPassword(strUserName,strPassword);
		}
		catch(AppException e)
		{
			if(e.getReason().equals("FSS-00006"))
			{
				// Get max failure count
				Statement stmt = null;
				try
				{
					stmt = mcn.createStatement();
					int iMaxFailureCount = 0;
					try
					{
						ResultSet rs = stmt.executeQuery("SELECT POLICY_VALUE FROM SEC_SYSTEM_POLICY WHERE POLICY_TYPE='MAX_LOGIN_FAILURE'");
						if(rs.next())
							iMaxFailureCount = rs.getInt(1);
						rs.close();
					}
					catch(Exception e1)
					{
					}

					if(iMaxFailureCount > 0)
					{
						stmt.executeUpdate("UPDATE SEC_USER SET STATUS=0,LAST_BLOCK_DATE=SYSDATE" +
										   " WHERE STATUS=1" +
										   " AND LOGIN_FAILURE_COUNT>=" + iMaxFailureCount +
										   " AND UPPER(USER_NAME)=UPPER('" + strUserName + "')");
					}
				}
				finally
				{
					Database.closeObject(stmt);
				}
			}
			throw e;
		}
	}
	////////////////////////////////////////////////////////
	/**
	 *
	 * @param strPolicy String
	 * @return String
	 * @throws Exception
	 */
	////////////////////////////////////////////////////////
	public String getPolicy(String strPolicy) throws Exception
	{
		String strReturn = mprtPolicyCache.getProperty(strPolicy);
		if(strReturn == null)
		{
			Vector vt = Database.executeQuery(mcn,"SELECT POLICY_VALUE" +
											  " FROM SEC_SYSTEM_POLICY" +
											  " WHERE UPPER(POLICY_TYPE)=UPPER('" + strPolicy + "')");
			if(vt.size() > 0)
				strReturn = (String)((Vector)vt.elementAt(0)).elementAt(0);
			strReturn = StringUtil.nvl(strReturn,"");
			mprtPolicyCache.setProperty(strPolicy,strReturn);
		}
		return strReturn;
	}
	////////////////////////////////////////////////////////
	/**
	 *
	 * @param cn Connection
	 * @return String
	 * @throws Exception
	 */
	////////////////////////////////////////////////////////
	public static String getLastAuthenticationChange(Connection cn) throws Exception
	{
		String strSQL = "SELECT PAR_VALUE FROM AP_PARAM WHERE PAR_TYPE='SYSTEM'" +
						" AND PAR_NAME='AUTHENTICATION_LAST_CHANGED'";
		Vector vt = Database.executeQuery(cn,strSQL);
		if(vt.size() > 0)
			return StringUtil.nvl(((Vector)vt.elementAt(0)).elementAt(0),"");
		return "";
	}
	////////////////////////////////////////////////////////
	/**
	 *
	 * @param cn Connection
	 * @return boolean
	 * @throws Exception
	 */
	////////////////////////////////////////////////////////
	public static synchronized boolean checkAuthenticationChange(Connection cn) throws Exception
	{
		String strLastAuthenticationChange = AppAuthenticator.getLastAuthenticationChange(cn);
		if(strLastAuthenticationChange.compareTo(mstrLastAuthenticationChange) > 0)
		{
			mstrLastAuthenticationChange = strLastAuthenticationChange;
			mprtPermissionCache.clear();
			mprtPolicyCache.clear();
//			System.out.println("Cache was cleared for update authentication change at " + new java.util.Date());
			return true;
		}
		return false;
	}
	////////////////////////////////////////////////////////
	/**
	 *
	 * @param cn Connection
	 * @return String
	 * @throws Exception
	 */
	////////////////////////////////////////////////////////
	public static String getLastConfigurationChange(Connection cn) throws Exception
	{
		String strSQL = "SELECT PAR_VALUE FROM AP_PARAM WHERE PAR_TYPE='SYSTEM'" +
						" AND PAR_NAME='CONFIGURATION_LAST_CHANGED'";
		Vector vt = Database.executeQuery(cn,strSQL);
		if(vt.size() > 0)
			return StringUtil.nvl(((Vector)vt.elementAt(0)).elementAt(0),"");
		return "";
	}
	////////////////////////////////////////////////////////
	/**
	 *
	 * @param cn Connection
	 * @return boolean
	 * @throws Exception
	 */
	////////////////////////////////////////////////////////
	public static synchronized boolean checkConfigurationChange(Connection cn) throws Exception
	{
		String strLastConfigurationChange = AppAuthenticator.getLastConfigurationChange(cn);
		if(strLastConfigurationChange.compareTo(mstrLastConfigurationChange) > 0)
		{
			mstrLastConfigurationChange = strLastConfigurationChange;
			mprtPermissionCache.clear();
			mprtPolicyCache.clear();
//			System.out.println("Cache was cleared for update configuration change at " + new java.util.Date());
			return true;
		}
		return false;
	}
	////////////////////////////////////////////////////////
	/**
	 *
	 * @param strUserName String
	 * @param strOldPassword String
	 * @param strNewPassword String
	 * @throws Exception
	 */
	////////////////////////////////////////////////////////
	public void changePassword(String strUserName,String strOldPassword,String strNewPassword) throws Exception
	{
		if(getPolicy("REQUIRE_STRONG_PASSWORD").equals("1"))
		{
			if(strOldPassword.equals(strNewPassword))
				throw new AppException("FSS-10014","validatePassword");
		}
		super.changePassword(strUserName,strOldPassword,strNewPassword);
	}
	////////////////////////////////////////////////////////
	/**
	 *
	 * @param strRealPassword String
	 * @throws Exception
	 */
	////////////////////////////////////////////////////////
	public void validatePassword(String strRealPassword) throws Exception
	{
		if(getPolicy("REQUIRE_STRONG_PASSWORD").equals("1"))
		{
			if(strRealPassword.equals(""))
				throw new AppException("FSS-10012","validatePassword");
		}

		int iMinPasswordLength = 0;
		try
		{
			iMinPasswordLength = Integer.parseInt(getPolicy("MINIMUM_PASSWORD_LENGTH"));
		}
		catch(Exception e)
		{
		}
		if(strRealPassword.length() < iMinPasswordLength)
			throw new AppException("FSS-10013","validatePassword",String.valueOf(iMinPasswordLength));
	}
	////////////////////////////////////////////////////////
	/**
	 *
	 * @param strUserID String
	 * @return boolean
	 * @throws Exception
	 */
	////////////////////////////////////////////////////////
	public boolean isPasswordExpired(String strUserID) throws Exception
	{
		// Get expire duration
		int iExpireDuration = 0;
		try
		{
			iExpireDuration = Integer.parseInt(getPolicy("PASSWORD_EXPIRE_DURATION"));
		}
		catch(Exception e)
		{
		}

		// Is password expire?
		Statement stmt = null;
		try
		{
			stmt = mcn.createStatement();
			String strSQL = "SELECT NVL(PASSWORD_EXPIRE_STATUS,0) FROM SEC_USER WHERE USER_ID=" + strUserID +
							" AND (NVL(PASSWORD_EXPIRE_STATUS,0)=0 OR LAST_CHANGE_PASSWORD IS NULL";
			if(iExpireDuration > 0)
				strSQL += " OR SYSDATE-LAST_CHANGE_PASSWORD>=" + iExpireDuration + ")";
			else
				strSQL += ")";
			ResultSet rs = stmt.executeQuery(strSQL);
			String strStatus = "";
			if(rs.next())
				strStatus = rs.getString(1);
			rs.close();

			boolean bReturn = false;
			if(strStatus.equals("1"))
			{
				stmt.executeUpdate("UPDATE SEC_USER SET PASSWORD_EXPIRE_STATUS=0 WHERE USER_ID=" + strUserID);
				bReturn = true;
			}
			else if(strStatus.equals("0"))
				bReturn = true;
			return bReturn;
		}
		finally
		{
			Database.closeObject(stmt);
		}
	}
}
